package org.tio.sitexxx.im.server.handler;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.sitexxx.im.common.Command;
import org.tio.sitexxx.im.common.CommandHandler;
import org.tio.sitexxx.im.common.ImPacket;
import org.tio.sitexxx.im.common.ImSessionContext;
import org.tio.sitexxx.im.common.bs.GroupChatNtf;
import org.tio.sitexxx.im.common.bs.JoinGroupNtf;
import org.tio.sitexxx.im.common.bs.JoinGroupReq;
import org.tio.sitexxx.im.common.bs.JoinGroupResp;
import org.tio.sitexxx.im.common.utils.ImUtils;
import org.tio.sitexxx.im.server.Ims;
import org.tio.sitexxx.service.model.main.ChatRecord;
import org.tio.sitexxx.service.model.main.User;
import org.tio.sitexxx.service.service.base.UserRoleService;
import org.tio.sitexxx.service.service.base.UserService;
import org.tio.sitexxx.service.service.conf.ConfService;
import org.tio.sitexxx.service.service.stat.ChatRecordService;
import org.tio.sitexxx.service.vo.Const;
import org.tio.sitexxx.service.vo.Const.JoinGroupResult;
import org.tio.sitexxx.service.vo.GroupStat;
import org.tio.sitexxx.service.vo.SimpleUser;
import org.tio.utils.SystemTimer;
import org.tio.utils.json.Json;
import org.tio.utils.lock.ListWithLock;
import org.tio.utils.lock.SetWithLock;

import cn.hutool.core.util.StrUtil;

/**
 * 
 * @author tanyaowu 
 * 2016年9月8日 下午3:59:14
 */
@CommandHandler(Command.JOIN_GROUP_REQ)
public class JoinGroupReqHandler implements ImServerHandler {
	private static Logger log = LoggerFactory.getLogger(JoinGroupReqHandler.class);

	public static final JoinGroupReqHandler me = new JoinGroupReqHandler();

	private static final int MAX_SIZE_HISTORY_ONCE_TIME = 600;

	public JoinGroupReqHandler() {
	}

	@Override
	public void handler(ImPacket packet, ChannelContext channelContext, boolean isWebsocket) throws Exception {
		ImSessionContext imSessionContext = ImUtils.getImSessionContext(channelContext);

		JoinGroupReq joinGroupReq = null;
		joinGroupReq = Json.toBean(packet.getBodyStr(), JoinGroupReq.class);

		String groupid = joinGroupReq.getG();
		JoinGroupResult result = checkJoin(joinGroupReq, channelContext, groupid, isWebsocket);

		if (result != JoinGroupResult.OK) {
			//			Tio.remove(channelContext, "进入群组" + g + "失败【" + result + "】");
			//			return;

			//进群响应
			JoinGroupResp joinGroupResp = new JoinGroupResp();
			joinGroupResp.setG(groupid);
			joinGroupResp.setResult(result.getValue());
			ImPacket joinRespPacket = new ImPacket(Command.JOIN_GROUP_RESP, joinGroupResp);
			Ims.send(channelContext, joinRespPacket);
			return;
		}

		imSessionContext.setGroupid(groupid);
		SimpleUser simpleUser = ImUtils.getHandshakeSimpleUser(channelContext);
		//		User curr = ImUtils.getUser(channelContext);
		simpleUser.setGroupid(groupid);
		if (simpleUser.getMay() != null) {
			simpleUser.getMay().setGroupid(groupid);
		}
		simpleUser.setTimeJoinGroup(SystemTimer.currTime);

		//		SimpleUser lastSimpleUser = imSessionContext.getLastLoginSimpleUser();
		//		if (lastSimpleUser != null) {
		//			lastSimpleUser.setGroupid(groupid);
		//		}

		//发历史消息
		Integer c = joinGroupReq.getC();
		if (c == null || c < 2) {
			ListWithLock<ChatRecord> listWithLock = ChatRecordService.me.getLastGroupChat(groupid);
			if (listWithLock != null) {
				List<ChatRecord> chatrecords = listWithLock.getObj();
				if (chatrecords != null && chatrecords.size() > 0) {
					ReadLock readLock = listWithLock.readLock();
					readLock.lock();
					try {
						//历史群聊消息，可以批量发送
						List<GroupChatNtf> groupChatNtfs = new ArrayList<>(Math.min(MAX_SIZE_HISTORY_ONCE_TIME, chatrecords.size()));
						for (int j = chatrecords.size() - 1; j >= 0; j--) {
							ChatRecord chatRecord = chatrecords.get(j);
							Integer uid = chatRecord.getUid();
							String groupid2 = chatRecord.getGroupid();
							SimpleUser chatUser;
							if (uid != null) {
								User fromuser = UserService.ME.getById(uid);
								if (fromuser == null) {
									log.info("用户id[{}]不存在，或者不合法, chatRecord:{}", uid, Json.toJson(chatRecord));
									continue;
								}
								if (UserRoleService.checkUserStatus(fromuser)) {
									chatUser = SimpleUser.fromUser(fromuser);

								} else {
									log.info("用户status不对, chatRecord:{}", Json.toJson(chatRecord));
									continue;
								}
							} else {
								log.info("uid is null, chatRecord:{}", Json.toJson(chatRecord));
								continue;
							}

							GroupChatNtf groupChatNtf = new GroupChatNtf();
							groupChatNtf.setHs((byte) 1);
							groupChatNtf.setC(chatRecord.getText());
							groupChatNtf.setF(chatUser);

							groupChatNtf.setG(groupid2);
							groupChatNtf.setT(chatRecord.getTime().getTime());

							groupChatNtf.setCt(chatRecord.getContenttype());

							//								if (StrUtil.isBlank(chatRecord.getMid())) {
							groupChatNtf.setMid(String.valueOf(chatRecord.getId()));
							//								} else {
							//									groupChatNtf.setMid(chatRecord.getMid());
							//								}

				

							groupChatNtfs.add(groupChatNtf);

							//如果群聊数据包过大，所以达到一定数量后，就先发送掉
							if (groupChatNtfs.size() >= MAX_SIZE_HISTORY_ONCE_TIME) {
								ImPacket imPacket = new ImPacket(Command.GROUP_CHAT_NTY, Json.toJson(groupChatNtfs));
								Ims.send(channelContext, imPacket);
								groupChatNtfs.clear();
							}
						}

						//如果群聊有数据，把群聊数据发出去
						if (groupChatNtfs.size() > 0) {
							ImPacket imPacket = new ImPacket(Command.GROUP_CHAT_NTY, Json.toJson(groupChatNtfs));
							Ims.send(channelContext, imPacket);
							groupChatNtfs.clear();
						}
					} finally {
						readLock.unlock();
					}
				}
			}
		}

		//绑定群组
		Tio.bindGroup(channelContext, Const.ImGroupType.REAL + groupid);
		Tio.bindGroup(channelContext, groupid);
		Tio.bindGroup(channelContext, org.tio.sitexxx.service.vo.Const.ImGroupType.ALL_IN_ONE);

		//进群响应
		JoinGroupResp joinGroupResp = new JoinGroupResp();
		joinGroupResp.setG(groupid);
		joinGroupResp.setResult(result.getValue());
		ImPacket joinRespPacket = new ImPacket(Command.JOIN_GROUP_RESP, joinGroupResp);
		Ims.send(channelContext, joinRespPacket);

		GroupStat groupStat = Ims.createGroupStat(groupid);

		// 暂时获取在所有页面上的用户
		groupStat = Ims.createGroupStat(org.tio.sitexxx.service.vo.Const.ImGroupType.ALL_IN_ONE);

		PageOnlineReqHandler.ME.clearCache(groupid);//进出群组要清空在线观众列表的数据

		// 暂时获取在所有页面上的用户
		PageOnlineReqHandler.ME.clearCache(org.tio.sitexxx.service.vo.Const.ImGroupType.ALL_IN_ONE);

		//让浏览器关闭页面
		if (isWebsocket) {
			//
			String token = ImUtils.getToken(channelContext);
			SetWithLock<ChannelContext> tokenSetWithLock = Tio.getChannelContextsByToken(channelContext.groupContext, token);
			if (tokenSetWithLock != null) {
				Set<ChannelContext> tokenSet = tokenSetWithLock.getObj();
				if (tokenSet.size() > 1) {
					ReadLock readLock = tokenSetWithLock.readLock();
					readLock.lock();
					try {
						tokenSet = tokenSetWithLock.getObj();
						ImPacket closePagePacket = new ImPacket(Command.CLOSE_PAGE);
						for (ChannelContext channelContext2 : tokenSet) {
							if (channelContext2.getId().equals(channelContext.getId())) {
								continue;
							}

							if (Tio.isInGroup(groupid, channelContext2)) {
								ImSessionContext imSessionContext_2 = org.tio.sitexxx.im.server.utils.ImUtils.getImSessionContext(channelContext2);
								if (imSessionContext_2.isWebsocket()) {
									Ims.send(channelContext2, closePagePacket);
								}
							}
						}
					} finally {
						readLock.unlock();
					}
				}
			}
		}

		//发进群通知
		JoinGroupNtf joinGroupNtf = new JoinGroupNtf();
		joinGroupNtf.setG(groupid);
		// 暂时获取在所有页面上的用户
		joinGroupNtf.setG(Const.ImGroupType.ALL_IN_ONE);

		joinGroupNtf.setOnline(groupStat.getOnline());
		joinGroupNtf.setU(simpleUser);
		joinGroupNtf.setCid(channelContext.getId());
		joinGroupNtf.setIpcount(Ims.getIpCount());
		//		joinGroupNtf.setLastLoginSimpleUser(imSessionContext.getLastLoginSimpleUser());

		ImPacket joinGroupNotify = new ImPacket(Command.JOIN_GROUP_NTY, joinGroupNtf);
		//		Ims.sendToGroup(groupid, joinGroupNotify);
		// 暂时获取在所有页面上的用户
		Ims.sendToGroup(Const.ImGroupType.ALL_IN_ONE, joinGroupNotify);

		//投放IM广告
		String joinNofity = ConfService.getString("im.join.notify.for.ad", null);
		if (StrUtil.isNotBlank(joinNofity)) {
			User user = UserService.ME.getAi();
			SimpleUser simpleUser1 = SimpleUser.fromUser(user);
			ImUtils.completeSimpleUser(simpleUser1, channelContext);

			GroupChatNtf groupChatNtf = new GroupChatNtf();
			groupChatNtf.setC(joinNofity);
			groupChatNtf.setF(simpleUser1);
			groupChatNtf.setG(groupid);
			ImPacket imPacket = new ImPacket(Command.GROUP_CHAT_NTY, "[" + Json.toJson(groupChatNtf) + "]");
			Ims.send(channelContext, imPacket);
		}

		//发送系统提醒
		joinNofity = ConfService.getString("im.join.notify", null);
		if (StrUtil.isNotBlank(joinNofity)) {
			User user = UserService.ME.getAi();
			SimpleUser simpleUser1 = SimpleUser.fromUser(user);
			ImUtils.completeSimpleUser(simpleUser1, channelContext);

			GroupChatNtf groupChatNtf = new GroupChatNtf();
			groupChatNtf.setC(joinNofity);
			groupChatNtf.setF(simpleUser1);
			groupChatNtf.setG(groupid);
			ImPacket imPacket = new ImPacket(Command.GROUP_CHAT_NTY, "[" + Json.toJson(groupChatNtf) + "]");
			Ims.send(channelContext, imPacket);
		}
	}

	//	private ImPacket create

	/**
	 * 进入逻辑判断：等级限制、密码限制(暂时不处理)
	 * @return
	 * @param isWebsocket 
	 * @param group 
	 * @param channelContext 
	 * @param joinGroupReq 
	 */
	private JoinGroupResult checkJoin(JoinGroupReq joinGroupReq, ChannelContext channelContext, String group, boolean isWebsocket) {
		//		int groupCount = Tio.groupCount(channelContext.groupContext, Const.ImGroupType.REAL + group);
		//		if (groupCount >= 4000) {
		//			return JoinGroupResult.FAIL_GROUP_FULL;
		//		}
		//		User user = org.tio.sitexxx.im.server.utils.ImUtils.getUser(channelContext);
		//		if (user == null) {
		//			if (groupCount >= 1000) {
		//				return JoinGroupResult.FAIL_TOURIST_NOT_ALLOWED;
		//			}
		//		}

		return JoinGroupResult.OK;
	}

}
